﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using RpcClient.Broadcast;
using RpcClient.Collect;
using RpcClient.Config;
using RpcClient.Helper;
using RpcClient.Identity;
using RpcClient.Interface;
using RpcClient.Model;
using RpcClient.Msg;
using RpcClient.RpcSysEvent;

using RpcHelper;
using RpcHelper.Config;
using RpcModel;

namespace RpcClient
{
    /// <summary>
    /// Rpc 客户端
    /// </summary>
    public class RpcClient
    {
        public static event Action InitComplate;
        #region 私有变量

        private static readonly SyncLock _Lock = new SyncLock();

        /// <summary>
        /// 本地事件
        /// </summary>
        private static readonly ILocalEventCollect _LocalEvent = new LocalEventCollect();

        /// <summary>
        /// 配置模块
        /// </summary>
        private static readonly ISysConfig _Config = new Collect.SysConfigCollect();
        /// <summary>
        /// 路由模块
        /// </summary>
        private static readonly ITcpRouteCollect _Route = new TcpRouteCollect();

        /// <summary>
        /// 订阅模块
        /// </summary>
        private static readonly IRpcSubscribeCollect _Subscribe = new RpcSubscribeCollect();

        private static readonly IRpcControlCollect _RpcServer = new RpcControlCollect();
        /// <summary>
        /// 事务模块
        /// </summary>
        private static readonly IRpcTranService _RpcTran = new RpcTranCollect();

        #endregion

        static RpcClient()
        {
            Unity.RegisterEvent += Unity_RegisterEvent;
            Unity.SetDefFindInterface(new Type[]
            {
                typeof(IExtendService)
            });
            _InitUnity();
            Unity.Load("RpcClient");
            AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
            AppDomain.CurrentDomain.GetAssemblies().ForEach(c =>
            {
                _LoadModular(c);
            });
            RemoteSysEvent.AddEvent<ResetServiceState>("Rpc_ResetState", _ResetState);
        }

        private static void _InitUnity()
        {
            Unity.RegisterInstance<IRpcService>(RpcService.Service);
            Unity.RegisterInstance<IConfigCollect>(LocalConfig.Local);
            Unity.RegisterInstance(RpcClient.LocalEvent);
            Unity.RegisterInstance(RpcClient.Unity);
            Unity.RegisterInstance(RpcClient._Route);
            Unity.RegisterInstance(RpcClient._Config);
            Unity.RegisterInstance(RpcClient._Subscribe);
            Unity.RegisterInstance(RpcClient._RpcTran);
        }

        private static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
        {
            Assembly assembly = args.LoadedAssembly;
            _LoadModular(assembly);
        }
        private static Type _ModularType = typeof(IRpcModular);
        private static void _LoadModular(Assembly assembly)
        {
            Type modular = assembly.GetTypes().FirstOrDefault(c => c.GetInterface(_ModularType.FullName) != null);
            if (modular != null)
            {
                _LoadModular(modular);
            }
            _LocalEvent.RegLocalEvent(assembly);
        }
        private static void Unity_RegisterEvent(IocBody body)
        {
            if (body.Form == ConfigDic.IExtendService)
            {
                IExtendService service = Unity.Resolve<IExtendService>(body.Name);
                service.Load(RpcService.Service);
            }
            if (body.Form == ConfigDic.IMapper)
            {
                IMapper mapper = Unity.Resolve<IMapper>(body.Name);
                MapperCollect.RegScheme(mapper);
            }
        }

        internal static void SendEvent(IRemoteConfig config, IRemote remote, object model, int retryNum)
        {
            RpcService.Service.SendEvent(config, remote, model, retryNum);
        }

        /// <summary>
        /// 是否正在关闭
        /// </summary>
        internal static bool IsClosing = false;


        #region 公有属性

        public static string ClientVer => WebConfig.ApiVerNum;
        public static string AppSecret => WebConfig.AppSecret;
        /// <summary>
        /// Rpc事件
        /// </summary>
        public static IRpcEvent RpcEvent
        {
            get;
            set;
        } = new RpcEvent();
        /// <summary>
        /// 本地事件总线
        /// </summary>
        public static ILocalEventCollect LocalEvent => _LocalEvent;
        /// <summary>
        /// 容器
        /// </summary>
        public static IUnityCollect Unity
        {
            get;
        } = new UnityCollect();


        /// <summary>
        /// 系统类型
        /// </summary>
        public static string SystemTypeVal => WebConfig.RpcSystemType;
        /// <summary>
        /// 系统组别
        /// </summary>
        public static string GroupTypeVal => RpcStateCollect.LocalConfig.SysGroup;
        /// <summary>
        /// 服务名称
        /// </summary>
        public static string ServerName => RpcStateCollect.ServerConfig.Name;

        /// <summary>
        /// 是否已初始化
        /// </summary>
        public static bool IsInit => RpcStateCollect.IsInit;
        /// <summary>
        /// 服务节点Id
        /// </summary>
        public static long ServerId => RpcStateCollect.ServerId;
        /// <summary>
        /// 当前消息源
        /// </summary>
        public static MsgSource CurrentSource => RpcStateCollect.LocalSource;
        /// <summary>
        /// 路由模块
        /// </summary>
        public static ITcpRouteCollect Route => _Route;
        /// <summary>
        /// 配置管理模块
        /// </summary>
        public static ISysConfig Config => _Config;
        /// <summary>
        /// 订阅模块
        /// </summary>
        public static IRpcSubscribeCollect Subscribe => _Subscribe;


        /// <summary>
        /// 中控模块
        /// </summary>
        internal static IRpcControlCollect RpcServer => _RpcServer;

        /// <summary>
        /// 事务模块
        /// </summary>
        public static IRpcTranService RpcTran => _RpcTran;

        #endregion


        #region 初始化
        /// <summary>
        /// 登陆服务中心
        /// </summary>
        /// <returns></returns>
        private bool _LoginCentralService()
        {
            if (_Lock.GetLock())
            {
                if (RpcStateCollect.InitServer(out string error))
                {
                    _Lock.Exit();
                    return true;
                }
                else
                {
                    _Lock.Reset();
                    string show = string.Format("mac:{0}\r\nappId:{1}\r\nSystemType:{2}\r\nSecret:{3}", WebConfig.Environment.Mac, WebConfig.AppId, WebConfig.RpcSystemType, WebConfig.AppSecret);
                    RpcLogSystem.AddFatalError("初始化OAuth失败!", show, error);
                    return false;
                }
            }
            else
            {
                return RpcStateCollect.IsInit;
            }
        }
        /// <summary>
        /// 登陆重试
        /// </summary>
        /// <param name="retry"></param>
        /// <returns></returns>
        private bool _RetryLogin(int retry)
        {
            Thread.Sleep(retry * 1000 % 5000);
            try
            {
                this._LoginCentralService();
                return true;
            }
            catch
            {
                return retry <= 5 && this._RetryLogin(retry);
            }
        }
        /// <summary>
        /// 初始化服务节点基础模块
        /// </summary>
        /// <exception cref="ErrorException"></exception>
        private void _InitRpcService()
        {
            //登陆
            if (!this._Login())
            {
                throw new ErrorException("rpc.oauth.init.error");
            }
            else
            {
                RpcService.Service.BeginInit();
                //加载基础配置系统模块
                SysConfigCollect.LoadSysConfig();
            }
        }
        /// <summary>
        /// 初始化缓存模块
        /// </summary>
        private void _InitCache()
        {

        }
        /// <summary>
        /// 登陆服务中心
        /// </summary>
        /// <returns></returns>
        private bool _Login()
        {
            return this._LoginCentralService() || this._RetryLogin(1);
        }

        /// <summary>
        /// 初始化模块
        /// </summary>
        private void _InitModular()
        {
            RpcService.Service.InitEvent();
            TrackCollect.Init();
            SysLogCollect.Init();
            BroadcastCollect.Init();
            IdentityService.InitServie();
            this._InitComplating();
            this._InitSocket();
            this._InitPipe();
            this._InitComplate();
        }

        private void _InitPipe()
        {
            if (RpcStateCollect.ServerConfig.IsEnablePipe)
            {
                string name = string.Concat("Rpc_Server_", RpcStateCollect.ServerId);
                PipeServer.Config.PipeConfig.DefaultPipeName = name;
                TrackCollect.EnableChange += (e) =>
                {
                    PipeServer.Config.PipeConfig.DefaultAllot = e.IsEnable ? new TrackPipeMsg() : new PipeMsg();
                };
                PipeServer.Config.PipeConfig.DefaultAllot = TrackCollect.IsEnable ? new TrackPipeMsg() : new PipeMsg();
                PipeServer.Config.PipeConfig.ServerKey = RpcStateCollect.ServerConfig.PublicKey;
                PipeServer.Config.PipeConfig.PipeEvent = new PipeEvent();
                PipeServer.PipeServer.Init();
            }
        }

        private void _InitSocket()
        {
            TrackCollect.EnableChange += (e) =>
            {
                SocketTcpServer.Config.SocketConfig.DefaultAllot = e.IsEnable ? new Msg.TrackTcpMsg() : new Msg.TcpMsg();
            };
            SocketTcpServer.Config.SocketConfig.DefaultAllot = TrackCollect.IsEnable ? new Msg.TrackTcpMsg() : new Msg.TcpMsg();
            SocketTcpServer.Config.SocketConfig.DefaultServerPort = RpcStateCollect.ServerConfig.ServerPort;
            SocketTcpServer.Config.SocketConfig.ServerKey = RpcStateCollect.ServerConfig.PublicKey;
            SocketTcpServer.Config.SocketConfig.SocketEvent = new TcpEvent();
            SocketTcpServer.SocketTcpServer.Init();
        }
        #endregion

        /// <summary>
        /// 检查授权Ip
        /// </summary>
        /// <param name="clientIp"></param>
        /// <returns></returns>
        internal static bool CheckAccreditIp(string clientIp)
        {
            return clientIp == ConfigDic.LocalIp || RpcStateCollect.OAuthConfig.CheckAccreditIp(clientIp);
        }
        /// <summary>
        /// 刷新服务节点状态
        /// </summary>
        /// <param name="state">服务状态</param>
        /// <returns>远程回复消息</returns>
        private static TcpRemoteReply _ResetState(ResetServiceState state)
        {
            RpcEvent.ServiceState(state.ServiceState);
            if (state.ServiceState != RpcServiceState.停用)
            {
                return null;
            }
            Close();
            return null;
        }
        /// <summary>
        /// 关闭服务
        /// </summary>
        private static void _Close()
        {
            SocketTcpServer.SocketTcpServer.CloseServer();//关闭TCP服务
            RpcStateCollect.Close();//释放进程信息
            _Subscribe.Dispose();//释放订阅队列
            _Route.Dispose();//释放事件
            RpcEvent.ServerClose();//触发关闭事件
            SocketTcpClient.TcpClient.CloseSocket();//释放TCP客户端链接
            RpcLogSystem.AddLog("服务已关闭!");
            LogSystem.CloseLog();//关闭日志
        }

        #region 公有方法
        /// <summary>
        /// 关闭服务
        /// </summary>
        public static void Close()
        {
            Close(WebConfig.RpcConfig.CloseDelayTime);
        }
        /// <summary>
        /// 关闭服务
        /// </summary>
        /// <param name="time">延迟释放时间(秒)</param>
        public static void Close(int time)
        {
            if (RpcClient.IsClosing)
            {
                return;
            }
            RpcClient.IsClosing = true;//设为关闭状态后续收到的请求返回固定错误码
            RpcHelper.TaskTools.TaskManage.StopTask();//停止定时任务
            RpcQueueCollect.Dispose();//关闭消息队列
            Thread.Sleep(time * 1000);//延迟等待正在处理的任务处理完成
            _Close();//关闭服务
        }
        /// <summary>
        /// 触发初始化完成事件
        /// </summary>
        private void _InitComplate()
        {
            if (InitComplate != null)
            {
                InitComplate();
            }
            RpcService.Service.StartUp();
        }
        private void _InitComplating()
        {
            RpcService.Service.StartUpIng();
        }

        /// <summary>
        /// 启动服务
        /// </summary>
        public static void Start()
        {
            RpcEvent.ServerStarting();
            RpcClient client = new RpcClient();
            client._InitRpcService();
            ServerLimitCollect.Init();
            client._InitModular();
            RpcEvent.ServerStarted();
            Process pro = Process.GetCurrentProcess();
            pro.EnableRaisingEvents = true;
            pro.Exited += new EventHandler((a, e) =>
            {
                RpcClient.Close();
            });
        }
        /// <summary>
        /// 获取授权码
        /// </summary>
        /// <returns></returns>
        public static RpcToken GetAccessToken()
        {
            if (!RpcTokenCollect.GetAccessToken(out RpcToken token, out string error))
            {
                throw new ErrorException(error);
            }
            return token;
        }

        public static void LoadModular<T>() where T : IRpcModular
        {
            _LoadModular(typeof(T));
        }
        private static void _LoadModular(Type type)
        {
            if (Unity.RegisterInstance(_ModularType, type, type.Namespace))
            {
                Load(type.Assembly);
                IRpcModular modular = Unity.Resolve<IRpcModular>(type.Namespace);
                modular.Init(RpcClient.Unity);
            }
        }
        /// <summary>
        /// 注册程序集中可用容器和事件
        /// </summary>
        /// <param name="assemblyName"></param>
        public static void Load(string assemblyName)
        {
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            Assembly obj = assemblies.Find(a => a.GetName().Name == assemblyName);
            if (obj != null)
            {
                Load(obj);
            }
        }
        /// <summary>
        /// 注册程序集中可用容器和事件
        /// </summary>
        /// <param name="assembly"></param>
        public static void Load(Assembly assembly)
        {
            Unity.Load(assembly);
            _LocalEvent.RegLocalEvent(assembly);
            new RpcRouteHelper().AddRoute(assembly);
            new RpcSubscribeHelper().AddRoute(assembly);
        }
        #endregion
    }
}
